package cn.qingyun.gis.modules.alongstreet.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.qingyun.gis.exception.CommonException;
import cn.qingyun.gis.minio.util.MinioTool;
import cn.qingyun.gis.modules.alongstreet.constant.StreetAddStatus;
import cn.qingyun.gis.modules.alongstreet.constant.StreetKwStatus;
import cn.qingyun.gis.modules.alongstreet.entity.AlongStreetProofread;
import cn.qingyun.gis.modules.alongstreet.entity.BusinessBoundary;
import cn.qingyun.gis.modules.alongstreet.mapper.AlongStreetProofreadMapper;
import cn.qingyun.gis.modules.alongstreet.request.StreetAddRequest;
import cn.qingyun.gis.modules.alongstreet.request.StreetKwRequest;
import cn.qingyun.gis.modules.alongstreet.request.StreetRequest;
import cn.qingyun.gis.modules.alongstreet.response.AlongStreetResponse;
import cn.qingyun.gis.modules.alongstreet.service.IAlongStreetProofreadService;
import cn.qingyun.gis.modules.alongstreet.service.IBusinessBoundaryService;
import cn.qingyun.gis.modules.express.constant.RedisContant;
import cn.qingyun.gis.modules.express.util.SyncTool;
import cn.qingyun.gis.modules.init.utils.CsvTool;
import cn.qingyun.gis.modules.init.utils.FutureTool;
import cn.qingyun.gis.modules.init.utils.PageTool;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import lombok.SneakyThrows;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author guest
 * @since 2024-03-20
 */
@Service
public class AlongStreetProofreadServiceImpl extends ServiceImpl<AlongStreetProofreadMapper, AlongStreetProofread> implements IAlongStreetProofreadService {
    @Resource
    private IBusinessBoundaryService iBusinessBoundaryService;
    @Resource
    private AlongStreetProofreadMapper alongStreetProofreadMapper;
    @Resource
    private RedissonClient redissonClient;


    @SneakyThrows
    @Override
    public IPage<AlongStreetResponse> queryPoiByParams(StreetRequest request) {
        if (ObjectUtil.isEmpty(request.getLon()) || ObjectUtil.isEmpty(request.getLat())) {
            throw new CommonException("经纬度不能为空~");
        }

        // 根据商圈id获取边界
        QueryWrapper<BusinessBoundary> boundaryQueryWrapper = new QueryWrapper<>();
        boundaryQueryWrapper.lambda().select(BusinessBoundary::getWkt).eq(BusinessBoundary::getBusinessId, request.getBusinessId()).last("and wkt is not null and ST_isValid(ST_GeomFromText(wkt))");
        List<BusinessBoundary> wktList = iBusinessBoundaryService.list(boundaryQueryWrapper);
        if (wktList.size() != 1) {
            throw new CommonException("沿街商铺id不唯一~");
        }

        // 获取当前商圈下沿街数据
        QueryWrapper<AlongStreetProofread> queryWrapper = new QueryWrapper<>();

        queryWrapper.select("along_street_proofread.*," + String.format("ST_Distance_Sphere(st_geomfromtext(CONCAT('point(',%s,' ',%s,')'),4326), points) AS distance", request.getLon(), request.getLat()))
                .apply(String.format("ST_Within(points,ST_GeomFromText('%s',4326))", wktList.get(0).getWkt()))
                .orderByAsc("distance");

        // 关键字查询
        if (ObjectUtil.isNotEmpty(request.getKeyword())) {
            queryWrapper.lambda().and(
                    qw -> qw.like(AlongStreetProofread::getStreetName, request.getKeyword())
                            .or()
                            .like(AlongStreetProofread::getStreetAddress, request.getKeyword())
            );
        }

        // 查询未确认状态数据
        if (ObjectUtil.isNotEmpty(request.getKwStatue())) {
            queryWrapper.lambda().eq(AlongStreetProofread::getKwStatue, request.getKwStatue());
        }

        // 查询已确认状态数据
        if (ObjectUtil.isNotEmpty(request.getConfirmStatue())) {
            queryWrapper.lambda()
                    .eq(AlongStreetProofread::getConfirmStatue, request.getConfirmStatue())
                    .eq(AlongStreetProofread::getKwStatue, 1);
        }

        IPage<AlongStreetProofread> page = new Page<>(request.getPageNum(), request.getPageSize());
        return PageTool.castToBean(alongStreetProofreadMapper.selectPage(page, queryWrapper), AlongStreetResponse.class);

    }

    @Override
    @Transactional
    public void importPoiCsv(MultipartFile file) {
        try {
            List<AlongStreetProofread> datas = CsvTool.transferFile(file.getInputStream(), AlongStreetProofread.class);
            if (CollUtil.isNotEmpty(datas)) {
                int batchSize = 200;
                int count = datas.size();
                int pages = count / batchSize + 1;
                SyncTool.doSync(pages, i -> {
                    int startIndex = i == 1 ? 0 : (i - 1) * batchSize;
                    int endIndex = Math.min(startIndex + batchSize, count);
                    List<AlongStreetProofread> dataBitch = datas.subList(startIndex, endIndex);
                    // 导入数据
                    for (AlongStreetProofread data : dataBitch) {
                        data.setCreateTime(DateUtil.date());
                    }
                    this.saveBatch(dataBitch);
                });

            }
        } catch (IOException e) {
            log.error("导入沿街POI数据出错！！");
            throw new CommonException(e);
        } finally {
            alongStreetProofreadMapper.updateWkt();
        }
    }

    @Override
    @Transactional
    public String streetProofread(StreetKwRequest request) {
        RLock rlock = redissonClient.getLock(RedisContant.STREET_PROOF_LOCK + request.getId());
        try {
            boolean lockRes = rlock.tryLock(10, TimeUnit.SECONDS);
            if (lockRes) {
                AlongStreetProofread alongStreetProofread = alongStreetProofreadMapper.selectById(request.getId());
                if (ObjectUtil.isEmpty(alongStreetProofread)) {
                    return "当前摸排沿街POI信息不存在，请联系管理员";
                }
                UpdateWrapper<AlongStreetProofread> updateWrapper = new UpdateWrapper<>();
                // 触发加载图片
                List<String> pictureList = request.getPictureList();
                List<String> imageList = Lists.newArrayList();
                if (ObjectUtil.isNotEmpty(request.getPictureList())) {
                    for (int i = 0; i < request.getPictureList().size(); i++) {
                        // 如果当前传入的是base64字符串
                        if (request.getPictureList().get(i).contains("base64")) {
                            String imageName = request.getId() + "_" + (i + 1) + ".jpg";
                            int index = i;
                            imageList.add(FutureTool.get(FutureTool.getFuture(() -> this.uploadBase64Image(imageName, pictureList.get(index)))));
                        } else {
                            imageList.add(request.getPictureList().get(i));
                        }
                    }
                }
                // 摸排字段不为空
                if (ObjectUtil.isNotEmpty(request.getConfirmStatue())) {
                    updateWrapper.lambda().eq(AlongStreetProofread::getId, request.getId())
                            .set(AlongStreetProofread::getConfirmStatue, request.getConfirmStatue())
                            .set(AlongStreetProofread::getKwStatue, StreetKwStatus.PROOFED)
                            .set(AlongStreetProofread::getUpdateTime, DateUtil.date());
                    // 存放图片名称
                    if (imageList.size() == 1) {
                        updateWrapper.lambda().set(AlongStreetProofread::getPhotoOne, imageList.get(0));
                        updateWrapper.lambda().set(AlongStreetProofread::getPhotoTwo, null);
                        updateWrapper.lambda().set(AlongStreetProofread::getPhotoThree, null);
                    }
                    if (imageList.size() == 2) {
                        updateWrapper.lambda().set(AlongStreetProofread::getPhotoOne, imageList.get(0));
                        updateWrapper.lambda().set(AlongStreetProofread::getPhotoTwo, imageList.get(1));
                        updateWrapper.lambda().set(AlongStreetProofread::getPhotoThree, null);
                    }
                    if (imageList.size() == 3) {
                        updateWrapper.lambda().set(AlongStreetProofread::getPhotoOne, imageList.get(0));
                        updateWrapper.lambda().set(AlongStreetProofread::getPhotoTwo, imageList.get(1));
                        updateWrapper.lambda().set(AlongStreetProofread::getPhotoThree, imageList.get(2));
                    }

                }
                this.update(updateWrapper);
                return "勘误成功！";
            }
            return "系统繁忙，请稍后再试";

        } catch (Exception e) {
            throw new CommonException(e.getMessage());
        } finally {
            rlock.unlock();
        }
    }

    @Override
    public String uploadBase64Image(String imageName, String imageBase64) {
        if (imageBase64.contains(",")) {
            imageBase64 = imageBase64.split(",")[1];
        }
        byte[] imageBytes = Base64.decode(imageBase64);
        String uploaded = MinioTool.uploadLocalBytes(imageName, imageBytes);

        if (CharSequenceUtil.isBlank(uploaded)) {
            throw new CommonException("图片上传失败，请重试");
        }
        return uploaded;
    }

    @Override
    public void downloadImage(HttpServletResponse response, String imagePath) {
        if (imagePath.endsWith("mp3")) {
            response.addHeader("Content-Type", "audio/mp3");
        }
        MinioTool.download(imagePath, response);
    }

    @Override
    @Transactional
    public void addStreet(StreetAddRequest request) {

        AlongStreetProofread alongStreetProofread = new AlongStreetProofread();
        BeanUtil.copyProperties(request, alongStreetProofread);
        alongStreetProofread.setId(IdUtil.getSnowflakeNextIdStr());

        if (ObjectUtil.isNotEmpty(request.getKwStatue())) {
            alongStreetProofread.setKwStatue(request.getKwStatue());
        }

        alongStreetProofread.setIsAdd(StreetAddStatus.ADD);
        alongStreetProofread.setCreateTime(DateUtil.date());

        // 触发加载图片
        List<String> imageList = Lists.newArrayList();
        if (ObjectUtil.isNotEmpty(request.getPictureList())) {
            for (int i = 0; i < request.getPictureList().size(); i++) {
                // 如果当前传入的是base64字符串
                if (request.getPictureList().get(i).contains("base64")) {
                    String imageName = IdUtil.getSnowflakeNextId() + "_" + (i + 1) + ".jpg";
                    int index = i;
                    imageList.add(FutureTool.get(FutureTool.getFuture(() -> this.uploadBase64Image(imageName, request.getPictureList().get(index)))));

                } else {
                    imageList.add(request.getPictureList().get(i));
                }
            }
            // 存放图片名称
            if (imageList.size() == 1) {
                alongStreetProofread.setPhotoOne(imageList.get(0));
            }
            if (imageList.size() == 2) {
                alongStreetProofread.setPhotoOne(imageList.get(1));
            }
            if (imageList.size() == 3) {
                alongStreetProofread.setPhotoOne(imageList.get(2));
            }
        }
        alongStreetProofreadMapper.saveStreet(alongStreetProofread);
    }
}






















